package com.myimooc.shiro.web.session;

import org.apache.shiro.session.Session;
import org.apache.shiro.session.UnknownSessionException;
import org.apache.shiro.session.mgt.eis.AbstractSessionDAO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.util.CollectionUtils;
import org.springframework.util.SerializationUtils;

import java.io.Serializable;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.TimeUnit;

import static com.myimooc.shiro.web.constant.Constants.Role.NUM600;

/**
 * @className: RedisSessionDao
 * @description: 使用redis管理session
 * @date: 2020/5/12
 * @author: cakin
 */
public class RedisSessionDao extends AbstractSessionDAO {
    /**
     * shiroSessionPrefix
     */
    private final String shiroSessionPrefix = "shiro-session:";

    /**
     * redisTemplate
     */
    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 功能描述：键以二进制
     *
     * @author cakin
     * @date 2020/5/12
     * @param key 键的字符串形式
     * @return byte[] 键的二进制形式
     * @description:
     */
    private byte[] getKey( String key ) {
        return (shiroSessionPrefix + key).getBytes();
    }

    /**
     * 功能描述：保存session
     *
     * @author cakin
     * @date 2020/5/12
     * @param session session变量
     */
    private void saveSession( Session session ) {
        if (session != null && session.getId() != null) {
            byte[] key = getKey(session.getId().toString()); // session对应的键
            byte[] value = SerializationUtils.serialize(session); // session对应的值
            redisTemplate.opsForValue().set(key, value, NUM600, TimeUnit.SECONDS); // 将session保存到redis中
        }
    }

    /**
     * 功能描述：创建session
     *
     * @author cakin
     * @date 2020/5/12
     * @param session session变量
     * @return Serializable
     * @description:
     */
    @Override
    protected Serializable doCreate( Session session ) {
        System.out.println("写入session");
        Serializable sessionId = generateSessionId(session);
        assignSessionId(session, sessionId);
        saveSession(session);
        return sessionId;
    }

    /**
     * 功能描述：根据sessionId读取session
     *
     * @author cakin
     * @date 2020/5/12
     * @param sessionId SessionId
     * @return Session Session
     * @description:
     */
    @Override
    protected Session doReadSession( Serializable sessionId ) {
        System.out.println("读取session");
        if (sessionId == null) {
            return null;
        }
        byte[] key = getKey(sessionId.toString()); // sessionId的对应的key
        byte[] value = (byte[]) redisTemplate.opsForValue().get(key); // sessionId的对应的value
        return (Session) SerializationUtils.deserialize(value); // 反序列化为Session对象
    }

    /**
     * 功能描述：其实就是保存
     *
     * @author cakin
     * @date 2020/5/12
     * @param session session变量
     */
    @Override
    public void update( Session session ) throws UnknownSessionException {
        saveSession(session);
    }
    /**
     * 功能描述：删除session，并在redis中删除
     *
     * @author cakin
     * @date 2020/5/12
     * @param session session
     */
    @Override
    public void delete( Session session ) {
        if (session == null || session.getId() == null) {
            return;
        }
        byte[] key = getKey(session.getId().toString());
        redisTemplate.opsForValue().getOperations().delete(key);
    }
    /**
     * 功能描述：从Redis中获得所有存活的Session
     *
     * @author cakin
     * @date 2020/5/12
     * @return Collection<Session> Session集合
     * @description:
     */
    @Override
    public Collection<Session> getActiveSessions() {
        Set<byte[]> keys = redisTemplate.opsForValue().getOperations().keys(shiroSessionPrefix + "*");
        Set<Session> sessions = new HashSet<>();
        if (CollectionUtils.isEmpty(keys)) {
            return sessions;
        }
        for (byte[] key : keys) {
            byte[] value = (byte[]) redisTemplate.opsForValue().get(key);
            sessions.add((Session) SerializationUtils.deserialize(value));
        }
        return sessions;
    }
}
